题目描述:

英语老师留了 N 篇阅读理解作业,但是每篇英文短文都有很多生词需要查字典,为了节约时间,现在要做个统计,算一算某些生词都在哪几篇短文中出现过

原题传送门->->

输入格式

第一行为整数 N ,表示短文篇数,其中每篇短文只含空格和小写字母。

按下来的 N 行,每行描述一篇短文。每行的开头是一个整数 L ,表示这篇短文由 L 个单词组成。接下来是 L 个单词,单词之间用一个空格分隔。

然后为一个整数 M ,表示要做几次询问。后面有 M 行,每行表示一个要统计的生词。

输出格式

对于每个生词输出一行,统计其在哪几篇短文中出现过,并按从小到大输出短文的序号,序号不应有重复,序号之间用一个空格隔开(注意第一个序号的前面和最后一个序号的后面不应有空格)。如果该单词一直没出现过,则输出一个空行。

输入输出样例

输入 #1

3

9 you are a good boy ha ha o yeah
13 o my god you like bleach naruto
one piece and so do i
11 but i do not think you will get all the
points
5 you i o all naruto

输出 #1

1 2 3

2 3

1 2

3

2

说明/提示

对于 30% 的数据, 1 ≤ M ≤ $10^3$。

对于 100%100\%100% 的数据,1 ≤ M ≤ $10^4$
1 ≤ N ≤ $10^3$ 。

每篇短文长度(含相邻单词之间的空格)≤ $5×10^3$字符,每个单词长度 ≤ 20 字符。

每个测试点时限 2 秒。

—————————————-分割线———————————————-

第一反应是用桶排,如果能把单词表示成一个编码,直接用int数组就可以做了,但是显然,20个字母组成的单词编码的数据会很大。

但我可以想到可以退而求其次:对字母的前两个字母进行编码,编码相同的单词存储到同一个map< string , list>中,string记录单词,list记录单词在哪几个文章中出现。这样的由于前两个字母都一样的单词很少,查找几乎是线性时间就能结束。

建立一个这样的数组存储所有的单词。
map >article[27][27];
编码使用如下规则

如何存储呢?假如是单词是“abc”,’a’ - ‘a’ + 1 = 1;‘b’ - ‘a’ + 1 = 2把它存在article[1][2]里。
特别的,仅有一个字母的单词,比如”a” 存储在article[1][0]中。

查找单词时按照同样的规则。

AC代码:

#include<iostream>
#include<string>
#include<map>
#include<list>
using namespace std;

map<string,list<int> >article[27][27];

string key;//待查询的单词

void Read(int n);//输入第n篇文章
void Solve();
int main()
{
    int n, m;
    cin >> n;
    for(int i = 1; i <= n; ++i)
    Read(i);

    cin >> m;
    for(int i = 0; i < m; ++i)
    {
        cin >> key;
        Solve();
    }
    return 0;
}

void Read(int n)
{
    int l;
    cin >> l;
    list<int>tmp;
    tmp.push_back(n);
    for(int i = 0; i < l; ++i)
    {
        string w;
        cin >> w;
        int c = w[0] - 'a' + 1;
        int d = 0;
        if(w.size() > 1)
        d = w[1] - 'a' + 1;//进行编码
        pair<map<string,list<int> >::iterator,bool> flag = article[c][d].insert(make_pair(w,tmp));
        if(!flag.second)//如果插入失败
            flag.first->second.push_back(n);
    }
}
void Solve()
{
    int a = key[0] - 'a' + 1;
    int b = 0;
    if(key.size() > 1)
        b = key[1] - 'a' + 1;
    map<string,list<int> >::iterator flag = article[a][b].find(key);
    if(flag != article[a][b].end())
    {
        list<int> *itr = &(flag->second);
        int tmp = itr->front();
        cout << tmp ;
        for(list<int>::iterator i = itr->begin(); i != itr->end(); ++i)
        {

            if(*i != tmp)
            {
                cout << " " << *i;
            }//注意list可能会插入多个相同的数值,所以需要与前一个数字比较判断
            tmp = *i;
        }
    }
    cout << endl;
}